import Utils from "../../../Utils";
import DestructibleFacility from "../../facility/DestructibleFacility";
import MoveComp, { MoveClamp } from "../../funcComp/MoveComp";
import { FacilityType } from "../../info/GameEnum";
import { Location, MapLength } from "../../info/Predefine";
import GameManager from "../../manager/GameManager";
import PlayerManager from "../../manager/PlayerManager";
import AiPlayer from "../AiPlayer";
import Player from "../Player";

const { ccclass, property } = cc._decorator;
const allDir = [cc.v3(-1, 0), cc.v3(1, 0), cc.v3(0, -1), cc.v3(0, 1)]
@ccclass
export default class AiFindHome extends cc.Component {

    //随机选择一个方向（上下左右）随机确定一个距离
    //按一定频率边走边寻找安家点(4*4的范围)
    //判断安家点周围是否有晶矿和油矿,有晶矿加20分(有其他晶矿递减一半)，有油矿加40分(有其他油矿递减一半);
    //按最终得分 0-100随机一次 判断是否再次安家 , 确认安家后寻路过去

    moveComp: MoveComp = null;
    aiPlayer: AiPlayer = null;

    //上一次移动的方向
    lastDir: cc.Vec3;
    targetHomeLocation: Location = null;
    //寻找到的目标安家点

    start() {
        this.moveComp = this.getComponent(MoveComp);
        this.aiPlayer = this.getComponent(AiPlayer);
        //开始移动
        this.scheduleOnce(this.moving.bind(this), Utils.getRandom(10, 30) / 10);
        this.scheduleOnce(this.looking.bind(this), 3);
    }

    /**
     * 移动
     */
    moving() {
        let position = this.node.position;
        let randomDir = this.getNextDir();
        let target: cc.Vec3;
        if (randomDir.x < 0) {
            let randomX = Utils.getRandom(0, position.x - MoveClamp[0].x);
            target = cc.v3(position.x - randomX, position.y)
        } else if (randomDir.x > 0) {
            let randomX = Utils.getRandom(0, MoveClamp[1].x - position.x);
            target = cc.v3(position.x + randomX, position.y)
        } else if (randomDir.y < 0) {
            let randomY = Utils.getRandom(0, position.y - MoveClamp[0].y);
            target = cc.v3(position.x, position.y - randomY)
        } else if (randomDir.y > 0) {
            let randomY = Utils.getRandom(0, MoveClamp[1].y - position.y);
            target = cc.v3(position.x, position.y + randomY)
        }
        // if (target.x < MoveClamp[0].x || target.x > MoveClamp[1].x || target.y < MoveClamp[0].y || target.y > MoveClamp[1].y) {
        //     cc.log(target);
        // }
        this.moveComp.setTarget(target, this.moving.bind(this));
    }

    /**
     * 寻找合适的安家点
     */
    looking() {
        //周围4*4的范围是否有安家点
        let foundHomes = this.getAroundHomes();
        if (foundHomes.length) {
            //8*8的范围内的矿得分
            let scores: number[] = foundHomes.map(this.getHomeScore);
            let maxIndex = Utils.findMaxIndex(scores);
            //随机 决定要不要去判断最大得分的安家点安家
            if (scores[maxIndex] > 15 && Utils.getRandom(0, 100) < scores[maxIndex]) {
                return this.gotoMakeHome(foundHomes[maxIndex]);
            }
        }
        this.scheduleOnce(this.looking.bind(this), Utils.getRandom(15, 25) / 10)
    }

    /**
     * 关闭移动和寻找安家点schedule
     * 寻路去目标安家点
     */
    gotoMakeHome(homeLocation: Location) {
        this.moveComp.setTarget(null, null);
        this.unscheduleAllCallbacks();
        this.targetHomeLocation = homeLocation;
        let homePosition = GameManager.instance.getGamePosition(homeLocation);
        //抵达
        let onArrive = () => {
            if (this.aiPlayer.makeHome())
                this.destroy();
        }

        //先X后Y，或者先Y后X
        if (Utils.getRandom(0, 1)) {
            this.moveComp.setTarget(cc.v3(homePosition.x, this.node.y), () => {
                this.moveComp.setTarget(cc.v3(this.node.x, homePosition.y), onArrive.bind(this));
            });
        } else {
            this.moveComp.setTarget(cc.v3(this.node.x, homePosition.y), () => {
                this.moveComp.setTarget(cc.v3(homePosition.x, this.node.y), onArrive.bind(this))
            })
        }
    }

    protected update(dt: number): void {
        if (this.targetHomeLocation) {
            let fac = GameManager.instance.getFacilityByLocation(this.targetHomeLocation);
            if (!fac || fac.facilityType != FacilityType.安家点 || this.aroundExistPlayer(this.targetHomeLocation)) {
                //重置
                this.moveComp.setTarget(null, null);
                this.targetHomeLocation = null;
                this.unscheduleAllCallbacks();
                this.moving();
                this.looking();
            }
        }
    }

    /**
     * 获取location安家点的得分
     * 8*8的范围内
     * 有晶矿加20分(有其他晶矿递减一半)，有油矿加40分(有其他油矿递减一半);
     * @returns 
     */
    private getHomeScore(homeLocation: Location): number {
        let score = 0;//得分
        let mine1Count = 0;//晶矿数量
        let mine2Count = 0;//油矿数量
        let otherCount = 0;//其他设施(敌人的)
        let minX = Math.max(homeLocation.locationX - 6, 0),
            maxX = Math.min(homeLocation.locationX + 6, MapLength - 1),
            minY = Math.max(homeLocation.locationY - 6, 0),
            maxY = Math.min(homeLocation.locationY + 6, MapLength - 1);
        for (let y = minY; y < maxY; y++) {
            for (let x = minX; x < maxX; x++) {
                let tempLocation = { locationX: x, locationY: y }
                let tempFacility = GameManager.instance.getFacilityByLocation(tempLocation);
                if (tempFacility) {
                    if (tempFacility.facilityType == FacilityType.晶矿) {
                        mine1Count++;
                    } else if (tempFacility.facilityType == FacilityType.油矿) {
                        mine2Count++;
                    } else if (tempFacility instanceof DestructibleFacility) {
                        otherCount++;
                    }
                }
            }
        }
        //晶矿得分
        let addScore = 10;
        for (let i = 0; i < mine1Count; i++) {
            score += addScore;
            addScore = addScore / 2;
        }
        //油矿得分
        addScore = 30;
        for (let i = 0; i < mine2Count; i++) {
            score += addScore;
            addScore = addScore / 2;
        }

        //有其他人，减分
        addScore = 80;
        for (let i = 0; i < otherCount; i++) {
            score -= addScore;
            addScore = addScore / 2;
        }

        return Math.max(score, 0);
    }


    private aroundExistPlayer(location: Location): boolean {
        let position = GameManager.instance.getGamePosition(location);
        return !!PlayerManager.instance.playerComps.find((player: Player) => player != this.aiPlayer && player.node.position.sub(position).len() < 1000)
    }

    /**
     * 获取当前位置附近的安家点位置
     * @returns 
     */
    private getAroundHomes(): Location[] {
        let location = GameManager.instance.getMapLocation(this.node.position);
        let minX = Math.max(location.locationX - 2, 0),
            maxX = Math.min(location.locationX + 2, MapLength - 1),
            minY = Math.max(location.locationY - 2, 0),
            maxY = Math.min(location.locationY + 2, MapLength - 1);
        //所发现的安家点
        let foundHomes: Location[] = [];
        for (let y = minY; y < maxY; y++) {
            for (let x = minX; x < maxX; x++) {
                let tempLocation = { locationX: x, locationY: y }
                let tempFacility = GameManager.instance.getFacilityByLocation(tempLocation);
                if (tempFacility && tempFacility.facilityType == FacilityType.安家点) {
                    foundHomes.push(tempLocation);
                }
            }
        }
        return foundHomes;
    }

    /**
     * 获取下一个要去的方向
     * 回头和继续走的方向可能性最小
     * @returns 
     */
    private getNextDir() {
        let readyDir: cc.Vec3[] = [];
        allDir.forEach(dir => {
            let time = this.lastDir && (dir.equals(this.lastDir) || this.lastDir.neg().equals(dir)) ? 1 : 4;
            for (let i = 0; i < time; i++)
                readyDir.push(dir);
        })
        this.lastDir = Utils.getRandomChoose(readyDir).clone();
        return this.lastDir;
    }

}
